package com.ttbj.core.protocol.http;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.alibaba.fastjson.JSON;
import com.google.common.reflect.TypeToken;
import com.ttbj.core.response.ResponseModel;
import com.ttbj.core.response.enums.ResponseCodeEnums;
import com.ttbj.core.util.JsonUtil;

/**
 * Http调用指定业务方法：如dubbo的facade、业务的Service
 * 
 * @author Daniel
 * @date 2018年1月27日 下午9:04:20
 * 
 */
public class HttpInvokeService implements ApplicationContextAware {
	private static Logger logger = LoggerFactory.getLogger(HttpInvokeService.class);

	/** 缓存service */
	private final Map<String, Class<?>> cacheMap = new HashMap<String, Class<?>>();

	protected ApplicationContext applicationContext;

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}

	/**
	 * Http调用指定业务方法：如dubbo的facade、业务的Service <br/>
	 * 只实现非重载Overload的方法（重载Overload的方法目前不支持）
	 * 
	 * @author Daniel
	 * @date 2018年1月27日 下午9:04:16
	 * 
	 * @param serviceClassFullName
	 *            类的全路径名
	 * @param methodName
	 *            方法名
	 * @param parameterListJson
	 *            参数list Json字符串，list元素的顺序必须和参数的顺序保持一致
	 * @return
	 */
	public String invoke(String serviceClassFullName, String methodName, String parameterListJson) {
		ResponseModel<String> responseModel = new ResponseModel<String>();
		logger.debug("input param:{}", parameterListJson);
		List<String> parameters = JsonUtil.jsonToListBean(parameterListJson, new TypeToken<ArrayList<String>>() {
			private static final long serialVersionUID = 2063127250078039029L;
		}.getType());

		try {
			Class<?> serviceCla = cacheMap.get(serviceClassFullName);
			if (serviceCla == null) {
				serviceCla = Class.forName(serviceClassFullName);
				logger.debug("serviceCla:" + JSON.toJSONString(serviceCla));

				// 设置缓存
				cacheMap.put(serviceClassFullName, serviceCla);
			}
			Method[] methods = serviceCla.getMethods();
			Method targetMethod = null;
			for (Method m : methods) {
				if (m.getName().equals(methodName)) {
					targetMethod = m;
					break;
				}
			}

			if (methodName == null) {
				logger.error("method is not correct,method={}", methodName);
				responseModel.setResponse(ResponseCodeEnums.FAILURE);
				responseModel.setMsg("method is not correct,method=" + methodName);
			}

			Object bean = this.applicationContext.getBean(serviceCla);
			Object result = null;
			Class<?>[] parameterTypes = targetMethod.getParameterTypes();
			if (parameterTypes.length == 0) {
				// 没有参数
				result = targetMethod.invoke(bean);
			} else {
				List<Object> jsonObjList = new ArrayList<Object>();
				if (parameters != null) {
					int i = 0;
					for (String parameter : parameters) {
						Class<?> clazz = parameterTypes[i];
						Object json = JsonUtil.jsonToBean(parameter, clazz);
						jsonObjList.add(json);
						i++;
					}

					Object[] jsonObjs = new Object[jsonObjList.size()];
					int j = 0;
					for (Object object : jsonObjList) {
						jsonObjs[j] = object;
						j++;
					}
					result = targetMethod.invoke(bean, jsonObjs);
				} else {
					logger.error("have none parameter");
					responseModel.setResponse(ResponseCodeEnums.FAILURE);
					responseModel.setMsg("have none parameter");
				}
			}
			return JSON.toJSONString(result);

		} catch (ClassNotFoundException e) {
			logger.error("class not found", e);
			responseModel.setResponse(ResponseCodeEnums.FAILURE);
			responseModel.setMsg("class not found");
		} catch (InvocationTargetException e) {
			logger.error("InvocationTargetException", e);
			responseModel.setResponse(ResponseCodeEnums.FAILURE);
			responseModel.setMsg("InvocationTargetException");
		} catch (IllegalAccessException e) {
			logger.error("IllegalAccessException", e);
			responseModel.setResponse(ResponseCodeEnums.FAILURE);
			responseModel.setMsg("IllegalAccessException");
		}
		return JSON.toJSONString(responseModel);
	}
}
